package edu.indiana.cs.b534.torrent.impl;


import edu.indiana.cs.b534.torrent.StorageManager;
import edu.indiana.cs.b534.torrent.TorrentException;
import edu.indiana.cs.b534.torrent.context.RequestBean;
import edu.indiana.cs.b534.torrent.context.TorrentContext;

import java.util.logging.Level;
import java.util.logging.Logger;

public class PieceRequestSender extends Thread {
    private static final int MINUTE = 60000;

    private final TorrentContext torrentContext;

    private int amountOfDataSentOnThisTimeSlice = 0;
    private long startTime = System.currentTimeMillis();

    private InfoCollector infoCollector;

    private static Logger logger = Logger.getLogger(TorrentManager.TORRENT_MANAGER_NAME);

    /**
     * @param torrentContext
     */
    public PieceRequestSender(TorrentContext torrentContext) {
        this.torrentContext = torrentContext;
        this.setDaemon(true);
        this.infoCollector = torrentContext.getInfoCollector();
    }

    @Override
    public void run() {
        while (true) {
            try {
                StorageManager storageManager = torrentContext.getStorageManager();
                if (storageManager == null) {
                    Thread.sleep(1000);
                    continue;
                }
                if (System.currentTimeMillis() - startTime >= MINUTE) {
                    startTime = System.currentTimeMillis();
                    logger.info("Upload rate for last minutes is " + amountOfDataSentOnThisTimeSlice / 1024 + "KB");
                    System.out.println("Upload rate for last minutes is " + amountOfDataSentOnThisTimeSlice / 1024 + "KB");
                    amountOfDataSentOnThisTimeSlice = 0;
//				}else if(amountOfDataSentOnThisTimeSlice > torrentContext.getBytesLeftToBeDownloaded()){
//					long timeLeftOnThistimeSlice =  MINUTE - (System.currentTimeMillis()-startTime);
//					logger.info("Quote for time time  slice is over, sleeping for  "+ timeLeftOnThistimeSlice + "ms");
//					Thread.sleep(timeLeftOnThistimeSlice);
                }


                RequestBean request = torrentContext.getRequestQueue().getRequest();

                PieceInfo pieceInfo = storageManager.getPieceInfo(request.getPieceIndex());
                int begin = request.getBegin();
                int length = request.getLength();
                int pieceIndex = request.getPieceIndex();
                if ((request.getBegin() + request.getLength()) <= pieceInfo.getPieceLength()) {


                    byte[] piece = storageManager.getPiece(request.getPieceIndex());
                    byte[] dataToBeSent = new byte[length];

                    //We do this to avoid array index out of bound on last block of the piece
                    System.arraycopy(piece, begin, dataToBeSent, 0, length);
                    try {
                        PeerInstance peerInstance = request.getPeerInstance();
                        peerInstance.sendPieceMessage(pieceIndex, begin, dataToBeSent);
                        logger.info("For peer " + request.getPeerInstance().getID() + " Block for piece " + pieceIndex + " from " + begin + " and length " + length + " is Added to queue");
                        //System.out.println("For peer "+ request.getPeerInstance().getID() + " Block for piece "+ pieceIndex + "from " + begin + " and length " + length + " is Added to queue");
                        amountOfDataSentOnThisTimeSlice = amountOfDataSentOnThisTimeSlice + length;
                    } catch (TorrentException e) {
                        if (request.getRetryCount() > 0) {
                            request.reduceRetryCount();
                            torrentContext.getRequestQueue().addWork(request);
                        }
                        logger.severe("Can not send piece to the peer. " + e);
                    }
                } else {
                    logger.log(Level.SEVERE, request.getPeerInstance().getID() + " is requesting a block " +
                            "inside the piece " + pieceIndex + ". But I do not have a block with the beginning index " + begin + " and length " + length);
                }

            } catch (Throwable e) {
                e.printStackTrace();
                logger.throwing(this.getClass().getName(), "run", e);
            }
        }
    }

}
